package com.jah.picavue.client;

import java.util.HashMap;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.History;
import com.jah.picavue.client.model.User;
import com.jah.picavue.client.EventBus;
import com.jah.picavue.client.PicaVue;
import com.jah.picavue.client.events.AlbumFeedRequestedEvent;
import com.jah.picavue.client.events.CancelTimerEvent;
import com.jah.picavue.client.events.GotAlbumFeedEvent;
import com.jah.picavue.client.events.GotUserFeedEvent;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
@SuppressWarnings("unchecked")
public class PicaVue implements EntryPoint, Config, ValueChangeHandler, AlbumFeedRequestedEvent.Handler {

	protected int curIndex = 0;
	protected HashMap callbacks = new HashMap();

	private User u = User.INSTANCE;
	private ViewManager viewmgr = ViewManager.INSTANCE;

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {

		// Get the picasa feed: path=user kind=album
		u.setUsername(readPrefUsername());
		String gdata = USERFEED.replace("$USERNAME$", u.getUsername());
		String callbackName = reserveCallback();
		setup(this, callbackName);
		addScript(gdata + callbackName);

		History.addValueChangeHandler(this);
		EventBus.get().addHandler(AlbumFeedRequestedEvent.TYPE, this);

	}
	
	// Get preferences
	public native String readPrefUsername() /*-{
	  return $wnd.picasa_username;
	}-*/;


	private String reserveCallback() {
		while (true) {
			if (!callbacks.containsKey(new Integer(curIndex))) {
				callbacks.put(new Integer(curIndex), null);
				return "__picavue_callback" + curIndex++;
			}
		}
	}


	public native static void setup(PicaVue p, String callback) /*-{
    	window[callback] = function(someData) {
      		p.@com.jah.picavue.client.PicaVue::json_callback(Lcom/google/gwt/core/client/JavaScriptObject;)(someData);
    	}
  	}-*/;


	public native void addScript(String url) /*-{
    	var elem = document.createElement("script");
    	elem.setAttribute("language", "JavaScript");
    	elem.setAttribute("src", url);
    	document.getElementsByTagName("body")[0].appendChild(elem);
  	}-*/;


	/**
	 * Handles JNSI callbacks from embedded scripts.  The scripts return either
	 * a user feed (this happens once at module load) or album feeds.
	 *
	 * @param jso JavaScriptObject from Picasa
	 */
	public void json_callback(JavaScriptObject jso) {
		JSONObject json = new JSONObject(jso);
		if (json == null || json.get("feed").isObject() == null) return;
		JSONArray entry_array = json.get("feed").isObject().get("entry").isArray();
		if (entry_array == null) return;
		if (json.get("feed").isObject().get("rights") == null) { // what kind of jso do we have?
			// fire a gotUserFeedEvent
			GotUserFeedEvent evt = new GotUserFeedEvent();
			evt.setFeed(json);
			EventBus.get().fireEvent(evt);
			// This seems like a good place to fire an initial History
			// state event.
		    History.fireCurrentHistoryState();
		} else {
			// fire a gotAlbumFeedEvent
			GotAlbumFeedEvent evt = new GotAlbumFeedEvent();
			evt.setFeed(json);
			EventBus.get().fireEvent(evt);
		}
	}


	/**
	 *
	 * onValueChange is called whenever History changes.
	 * The event value (url fragment) is carefully parsed to determine the next
	 * page view type and whether an album has been selected.
	 * The default view is the index view if the url fragment doesn't make
	 * sense.
	 *
	 */
	public void onValueChange(ValueChangeEvent event) {
		String frag = new String((String)event.getValue());
		if ( frag.length() == 0 ) {
			History.newItem("index", false);
		} else if (frag.equalsIgnoreCase("index")) {
			// No-Op
		} else {
			String[] f = frag.split("\\+");
			if (f.length == 2) {
				if (u.isAlbum(f[1]) &&
				(f[0].equalsIgnoreCase("slideshow") ||
				 f[0].equalsIgnoreCase("gallery"))) {
					viewmgr.doAlbumView(f[0].toLowerCase(), f[1]);
					return;
				} else {
					// TODO delete current bad item?
					History.newItem("index", false);
				}
			} else {
				// TODO delete current bad item?
				History.newItem("index", false);
			}
		}
		EventBus.get().fireEvent( new CancelTimerEvent() );
		viewmgr.doIndex(History.getToken());
	}
	

	public void onAlbumFeedRequested(AlbumFeedRequestedEvent evt) {
		String id = evt.getID();
		if (u.isAlbum(id)) {
			id = ALBUMFEED.replace("$USERNAME$", u.getUsername()).replace("$ALBUMID$", id);
			String callbackName = reserveCallback();
			setup(this, callbackName);
			addScript(id + callbackName);
		}
	}
}
